﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Logic.ClarizenSvc;

namespace Logic.ClarizenObjects
{
    public class TimeSheet: BaseObject
    {
        public Duration Duration { get; set; }
        public DateTime? ReportedDate { get; set; }

        public GenericEntity WorkItem { get; set; }
        [Clarizen(Editable = false, Selectable = true)]
        public int WorkItem_PercentCompleted { get; set;}
        [Clarizen(Editable = false, Selectable = true)]
        public String WorkItem_Name { get; set; }
        [Clarizen(Editable = false, Selectable = true)]
        public Duration WorkItem_ActualEffort { get; set; }
        [Clarizen(Editable = false, Selectable = true)]
        public Duration WorkItem_RemainingEffort { get; set; }

        public String Comment { get; set; }
        public Boolean RegularHours { get; set; }

        [Clarizen]
        public String WorkItemID
        {
            get { return WorkItem != null && WorkItem.Id != null ? WorkItem.Id.Value : ""; }
            set { WorkItem = new GenericEntity { Id = new EntityId { TypeName = "WorkItem", Value = value } }; }
        }

        public GenericEntity State { get; set; }
        [Clarizen]
        public Boolean? isApproved { get { return this.State != null? this.State.Id.Value == "Approved": new Boolean?(); } }
        [Clarizen]
        public Boolean? isSubmited { get { return this.State != null ? this.State.Id.Value != "Un Submitted" && this.State.Id.Value != "Approved" : new Boolean?(); } }

        public static Dictionary<String, TimeSheetViewItem> GetTimeSheet(DateTime start, DateTime end, int page, string userID, string projectID, out Boolean hasMore, out long totalCount)
        {
            totalCount = 0;
            var qc = new QueryComponent();
            // create quey to get all relevant workitems
            TimesheetViewQuery query1 = new TimesheetViewQuery 
            {
                Fields = new string[] { "Name", "PercentCompleted", "SYSID", "StartDate", "DueDate", "RemainingEffort", "ActualEffort", "Parent", "Parent.Name", "IndividualReporting", "Manager" },
                StartDate = start,
                Orders = new OrderBy[]{new OrderBy{FieldName="Name", Order=Order.Ascending, OrderSpecified=true}},
                EndDate = end, 
                Count = 20, 
                TypeName = "WorkItem",
                Paging = new Paging { PageSize=20, PageSizeSpecified =true, PageNumber=page, PageNumberSpecified=true},
            };
            // filter by user
            if (!string.IsNullOrEmpty(userID))
                query1.UserId = new EntityId {TypeName="User", Value=userID};
            And where = new And();
            var conds = new List<Condition>();
            // filter by project // TODO: Fix does not work
            if (!string.IsNullOrEmpty(projectID))
                conds.Add(new Compare { LeftExpression = new FieldExpression { FieldName = "ParentProject" }, Operator = Operator.Equal, RightExpression = new ConstantExpression { Value = new EntityId {Value=projectID, TypeName="Project" } } });
            where.Conditions = conds.ToArray();
            query1.Where = where;

             //TODO: Fix does not work problem with api
            //if (page == 0)
            //{
            //    var cq = new CountQuery { Query = query1 };
            //    totalCount = ((CountQueryResult)qc.Execute(cq)[0]).Count;
            //}

            var res = qc.Execute(query1);
            hasMore = ((QueryResult)(res[0])).Paging.HasMore;
            var workItems = ((QueryResult)res[0]).Entities.Select(e=> BaseObject.Intitialize<WorkItem>((GenericEntity)e)).ToList();

            if (workItems.Count == 0)
                return new Dictionary<string, TimeSheetViewItem>();

            Task.GetTaskResources(workItems);
            
            // get all timesheets for workitems    
            TimesheetQuery query2 = new TimesheetQuery 
            {
                WorkItems = workItems.Select(e => e.ID).ToArray(),
                Fields = TimeSheet.GetFields(typeof(TimeSheet)),
                Where = new And
                {
                    Conditions = new Condition[]{
                        new Compare {LeftExpression = new FieldExpression{FieldName="ReportedDate"}, Operator = Operator.GreaterThanOrEqual, RightExpression = new ConstantExpression{Value = start} },
                        new Compare {LeftExpression = new FieldExpression{FieldName="ReportedDate"}, Operator = Operator.LessThan, RightExpression = new ConstantExpression{Value = end} }
                    }
                }
            };
            res = qc.Execute(query2);
            var entities = ((QueryResult) res[0]).Entities.Select(e=> TimeSheet.Intitialize<TimeSheet>((GenericEntity)e)).ToList();
            // arrange data for displaying in table
            return TimeSheetViewItem.GetTimeSheetView(start, entities, workItems);
        }
    }

    public class TimeSheetViewItem
    {
        public WorkItem WorkItem {get;set;}
        public Dictionary<String, TimeSheet> TimeSheets {get;set;}

        // creates a table with rows of work items and cells of timesheets
        // if there are 2 timesheets for the same day for the same work item an extra row is added for that work item
        public static Dictionary<String,TimeSheetViewItem> GetTimeSheetView(DateTime start, List<TimeSheet> timeSheets, List<WorkItem> workItems)
        {
            Dictionary<String,TimeSheetViewItem> TimeSheetView = new  Dictionary<string,TimeSheetViewItem>();
            // create a row for each workitem
            foreach (var wi in workItems)
                TimeSheetView[wi.ID.Value + 0] = new TimeSheetViewItem { WorkItem = wi, TimeSheets = new Dictionary<string, TimeSheet>() };

            foreach (var item in timeSheets)
	        {
		        TimeSheetViewItem vi = null;
                int dayIndex = (item.ReportedDate.Value.Date - start.Date).Days;

                var index = 0;
                // iterate over all rows of the current work item
                while(TimeSheetView.ContainsKey(item.WorkItem.Id.Value + index))
                {
                    var current = TimeSheetView[item.WorkItem.Id.Value + index];
                    // if current work item has a record for current day continue to next record
                    if(current.TimeSheets.ContainsKey(dayIndex.ToString()))
                        index++;
                    else // add time sheet to current work item
                    {
                        vi = current;
                        break;
                    }
                }
                // create a new record to hold the timesheet if no empty one was found
                if(vi == null)
                {
                    vi = new TimeSheetViewItem { WorkItem = TimeSheetView[item.WorkItem.Id.Value + 0].WorkItem, TimeSheets = new Dictionary<string, TimeSheet>() };
                    TimeSheetView[item.WorkItem.Id.Value + index] = vi;
                }

                vi.TimeSheets.Add(dayIndex.ToString(), item);
                item.WorkItem = null;
	        }

            return TimeSheetView;
        }
    }
}
